package com.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.green.model.v20180509.ImageSyncScanRequest;
import com.aliyuncs.green.model.v20180509.VideoAsyncScanRequest;
import com.aliyuncs.green.model.v20180509.VideoAsyncScanResultsRequest;
import com.aliyuncs.http.FormatType;
import com.aliyuncs.http.HttpResponse;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.http.ProtocolType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.domain.Issue;
import com.domain.IssueComment;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mapper.helping.IssueCommentResponseMapper;
import com.qiniu.common.QiniuException;
import com.service.IIssueCommentResponseGrandsonService;
import com.service.IIssueCommentService;
import com.service.IIssueService;
import com.service.ILabelService;
import com.service.living.OfficialMessageService;
import com.service.living.SendDingMessageService;
import living.com.domain.DingMessage;
import living.com.domain.OfficialMessageType;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;


import java.io.UnsupportedEncodingException;
import java.util.*;

/**
 * <p>
 *     阿里云图片和视频审核工具类
 * </p>
 * @author 大忽悠
 * @create 2022/2/13 13:34
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class AliYunUtil {
    private static final ObjectMapper objectMapper=new ObjectMapper();
    private static final String access_key="LTAI5tAyYzevLEg3w5oJdQEB";
    private static final String access_secret="rx33EMTzWYcqE1fIb0HL6fTgkhg9Xv";
    private final OfficialMessageService officialMessageService;
    private final IssueCommentResponseMapper issueCommentResponseMapper;
    private final IIssueService iIssueService;
    private final QiNiuYunUtils qiNiuYunUtils;
    private final ILabelService iLabelService;
    private final IIssueCommentService iIssueCommentService;
    private final IIssueCommentResponseGrandsonService iIssueCommentResponseGrandsonService;

    @Async("DhyExecutor")
    public  void checkImg(List<String> urls, WeiXinUtil.WeiXinCheckTextType textType, int text_id, int publisherId, String openId) throws QiniuException, JsonProcessingException {
        //判断是否有图片需要进行审核
        if(urls==null||urls.size()==0)
        {
            return;
        }
        for (String url : urls) {
            //审核不通过
            if (!doCheckImg(url)) {
                //消息格式
                StringBuilder stringBuilder=new StringBuilder();
                stringBuilder.append(publisherId+"号用户发布的"+text_id+"号");
                //删除当前文本关联的所有图片资源和视频资源
                delTextFiles(text_id,textType);
                //删除指定文本消息
                synchronized (this)
                {
                    logicDelText(text_id,textType,stringBuilder);
                }
                stringBuilder.append("图片审核未通过");
                //发送钉钉消息
                SendDingMessageService.sendContentAuditMessage
                        (new DingMessage(stringBuilder.toString()));
                //给发布者发布官方消息
                officialMessageService.sendOfficialMessage("您的动态含有违规内容,已被管理员删除", null, publisherId, OfficialMessageType.PUNISH);
                //一个图片审核失败,就退出审核
                break;
            }
        }
    }


    private void delTextFiles(int text_id, WeiXinUtil.WeiXinCheckTextType textType) throws JsonProcessingException, QiniuException {
        //回答
        String imgs=null;
        String videos=null;
        if (textType.equals(WeiXinUtil.WeiXinCheckTextType.FATHER_COMMENT)) {
            IssueComment issueComment = iIssueCommentService.getById(text_id);
            imgs = issueComment.getImgs();
            videos = issueComment.getVideos();
        }
        //问题
        else if (textType.equals(WeiXinUtil.WeiXinCheckTextType.ISSUE_TITLE) || textType.equals(WeiXinUtil.WeiXinCheckTextType.ISSUE_DETAILS)) {
            Issue issue = iIssueService.getById(text_id);
            imgs=issue.getImgs();
            videos=issue.getVideos();
        }
        commonFileDelOperations(imgs);
        commonFileDelOperations(videos);
    }

    private void commonFileDelOperations(String paths) throws QiniuException, JsonProcessingException {
        if(paths!=null&&!paths.equals("")&&!paths.equals("[]"))
        {
            qiNiuYunUtils.deleteFileJson(paths);
        }
    }

    /**
     * 逻辑删除---隐式删除
     */
    private void logicDelText(int text_id, WeiXinUtil.WeiXinCheckTextType textType, StringBuilder stringBuilder)
    {
        if (textType.equals(WeiXinUtil.WeiXinCheckTextType.FATHER_COMMENT)) {
            //删除父评论
            iIssueCommentService.WeiXinDel(text_id);
            stringBuilder.append("父评论");
        } else if (textType.equals(WeiXinUtil.WeiXinCheckTextType.SON_COMMENT)) {
            //子评论审核不通过
            issueCommentResponseMapper.logicDelById(text_id);
            stringBuilder.append("子评论");
        } else if (textType.equals(WeiXinUtil.WeiXinCheckTextType.ISSUE_TITLE) || textType.equals(WeiXinUtil.WeiXinCheckTextType.ISSUE_DETAILS)) {
            //问题审核不通过
            iIssueService.WeiXinDel(text_id);
            stringBuilder.append("问题");
        }else if(textType.equals(WeiXinUtil.WeiXinCheckTextType.LABEL_CONTENT))
        {
            //标签内容审核失败
            iLabelService.delTargetLabel(text_id);
            stringBuilder.append("标签");
        }
    }

    public boolean doCheckImg(String url)
    {
        IClientProfile profile = DefaultProfile
                .getProfile("cn-shanghai", access_key, access_secret);
        DefaultProfile
                .addEndpoint("cn-shanghai", "Green", "green.cn-shanghai.aliyuncs.com");
        IAcsClient client = new DefaultAcsClient(profile);
        ImageSyncScanRequest imageSyncScanRequest = new ImageSyncScanRequest();
        // 指定API返回格式。
        imageSyncScanRequest.setAcceptFormat(FormatType.JSON);
        // 指定请求方法。
        imageSyncScanRequest.setMethod(MethodType.POST);
        imageSyncScanRequest.setEncoding("utf-8");
        // 支持HTTP和HTTPS。
        imageSyncScanRequest.setProtocol(ProtocolType.HTTP);

        JSONObject httpBody = new JSONObject();
        /**
         * 设置要检测的风险场景。计费依据此处传递的场景计算。
         * 一次请求中可以同时检测多张图片，每张图片可以同时检测多个风险场景，计费按照场景计算。
         * 例如，检测2张图片，场景传递porn和terrorism，计费会按照2张图片鉴黄，2张图片暴恐检测计算。
         * porn：表示鉴黄场景。
         */
        httpBody.put("scenes", Arrays.asList("porn","terrorism"));

        /**
         * 设置待检测图片。一张图片对应一个task。
         * 多张图片同时检测时，处理的时间由最后一个处理完的图片决定。
         * 通常情况下批量检测的平均响应时间比单张检测的要长。一次批量提交的图片数越多，响应时间被拉长的概率越高。
         * 这里以单张图片检测作为示例, 如果是批量图片检测，请自行构建多个task。
         */
        JSONObject task = new JSONObject();
        task.put("dataId", UUID.randomUUID().toString());
        // 设置图片链接。
        task.put("url", url);
        task.put("time", new Date());
        httpBody.put("tasks", Arrays.asList(task));

        imageSyncScanRequest.setHttpContent(org.apache.commons.codec.binary.StringUtils.getBytesUtf8(httpBody.toJSONString()),
                "UTF-8", FormatType.JSON);

        /**
         * 请设置超时时间。服务端全链路处理超时时间为10秒，请做相应设置。
         * 如果您设置的ReadTimeout小于服务端处理的时间，程序中会获得一个ReadTimeout异常。
         */
        imageSyncScanRequest.setConnectTimeout(3000);
        imageSyncScanRequest.setReadTimeout(10000);
        HttpResponse httpResponse = null;
        try {
            httpResponse = client.doAction(imageSyncScanRequest);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 服务端接收到请求，完成处理后返回的结果。
        if (httpResponse != null && httpResponse.isSuccess()) {
            JSONObject scrResponse = JSON.parseObject(org.apache.commons.codec.binary.StringUtils.newStringUtf8(httpResponse.getHttpContent()));
            System.out.println(JSON.toJSONString(scrResponse, true));
            int requestCode = scrResponse.getIntValue("code");
            // 每一张图片的检测结果。
            JSONArray taskResults = scrResponse.getJSONArray("data");
            if (200 == requestCode) {
                for (Object taskResult : taskResults) {
                    // 单张图片的处理结果。
                    int taskCode = ((JSONObject) taskResult).getIntValue("code");
                    // 图片对应检测场景的处理结果。如果是多个场景，则会有每个场景的结果。
                    JSONArray sceneResults = ((JSONObject) taskResult).getJSONArray("results");
                    if (200 == taskCode) {
                        for (Object sceneResult : sceneResults) {
                            String scene = ((JSONObject) sceneResult).getString("scene");
                            String suggestion = ((JSONObject) sceneResult).getString("suggestion");
                            // 根据scene和suggestion做相关处理。
                            // 根据不同的suggestion结果做业务上的不同处理。例如，将违规数据删除等。
                           log.info("当前审核的场景为 scene = [" + scene + "]");
                            log.info("当前审核结果的建议为 suggestion = [" + suggestion + "]");
                            if(!suggestion.equals("pass"))
                            {
                                return false;
                            }
                        }
                        return true;
                    } else {
                        // 单张图片处理失败, 原因视具体的情况详细分析。
                        log.error("task process fail. task response:" + JSON.toJSONString(taskResult));
                        return false;
                    }
                }
            } else {
                /**
                 * 表明请求整体处理失败，原因视具体的情况详细分析。
                 */
                log.error("the whole image scan request failed. response:" + JSON.toJSONString(scrResponse));
                return false;
            }
        }
        return false;
    }


    @Async("DhyExecutor")
    public void videoCheck(List<String> videoUrl, WeiXinUtil.WeiXinCheckTextType textType, int text_id, int publisherId, String openId) throws UnsupportedEncodingException, ClientException, JsonProcessingException, QiniuException {
        //异步审核,通过轮询处理
        if(videoUrl!=null&&videoUrl.size()>0) {
            String taskId = doVideoCheck(videoUrl.get(0));
            if (taskId == null) {
                //删除相关资源
//                synchronized (this)
//                {
//                    //TODO:是否需要通知对应用户,系统产生的错误导致资源上传失败
//                    delTextFiles(text_id, textType);
//                }
                //先不进行删除,不错杀
                return;
            }
            //30秒后进行第一轮视频检查
            synchronized (this)
            {
                try {
                    this.wait(1000*30);
                } catch (InterruptedException e) {
                    log.error("被唤醒了....");
                }
            }
            Integer integer = doLoopGetVideoCheckRes(taskId);
            int addr=1;
            while (integer == 280) {
                //轮询看视频是否审核完毕
                if(addr>=10)
                {
                    integer=-1;
                    break;
                }
                //沉睡30秒
                try {
                    addr++;
                    synchronized (this)
                    {
                        this.wait(1000 * 30);
                    }
                } catch (InterruptedException e) {
                    log.error("被唤醒...");
                }
                integer = doLoopGetVideoCheckRes(taskId);
            }
            if (integer == -1) {
                //删除相关资源
               synchronized (this)
               {
                   //消息格式
                   StringBuilder stringBuilder=new StringBuilder();
                   stringBuilder.append(publisherId+"号用户发布的"+text_id+"号");
                   //删除当前文本关联的所有图片资源和视频资源
                   delTextFiles(text_id,textType);
                   //删除指定文本消息
                   synchronized (this)
                   {
                       logicDelText(text_id,textType,stringBuilder);
                   }
                   stringBuilder.append("视频审核未通过");
                   //发送钉钉消息
                   SendDingMessageService.sendContentAuditMessage
                           (new DingMessage(stringBuilder.toString()));
                   //给发布者发布官方消息
                   officialMessageService.sendOfficialMessage("您的动态含有违规内容,已被管理员删除", null, publisherId, OfficialMessageType.PUNISH);
                   //删除相关文件
                   delTextFiles(text_id, textType);
               }
            }
        }
    }



    public static String doVideoCheck(String url) throws ClientException, UnsupportedEncodingException, JsonProcessingException {
        IClientProfile profile = DefaultProfile.getProfile("cn-shanghai", access_key, access_secret);
        DefaultProfile.addEndpoint("cn-shanghai", "Green", "green.cn-shanghai.aliyuncs.com");
        IAcsClient client = new DefaultAcsClient(profile);

        VideoAsyncScanRequest videoAsyncScanRequest = new VideoAsyncScanRequest();
        videoAsyncScanRequest.setAcceptFormat(FormatType.JSON); // 指定API返回格式。
        videoAsyncScanRequest.setMethod(com.aliyuncs.http.MethodType.POST); // 指定请求方法。

        List<Map<String, Object>> tasks = new ArrayList<Map<String, Object>>();
        Map<String, Object> task = new LinkedHashMap<String, Object>();
        task.put("dataId", UUID.randomUUID().toString());
        task.put("url", url);

        tasks.add(task);
        /**
         * 设置要检测的场景。计费是依据此处传递的场景计算。
         * 视频默认1秒截取一帧，您可以自行控制截帧频率。收费按照视频的截帧数量以及每一帧的检测场景计算。
         * 举例：1分钟的视频截帧60张，检测色情（对应场景参数porn）和暴恐涉政（对应场景参数terrorism）2个场景，收费按照60张色情+60张暴恐涉政进行计费。
         */
        JSONObject data = new JSONObject();
        data.put("scenes", Arrays.asList("porn", "terrorism"));
        data.put("tasks", tasks);

        videoAsyncScanRequest.setHttpContent(data.toJSONString().getBytes("UTF-8"), "UTF-8", FormatType.JSON);

        /**
         * 请务必设置超时时间。
         */
        videoAsyncScanRequest.setConnectTimeout(3000);
        videoAsyncScanRequest.setReadTimeout(6000);
        HttpResponse httpResponse = client.doAction(videoAsyncScanRequest);
        if (httpResponse.isSuccess()) {
            JSONObject jsonObject = JSON.parseObject(new String(httpResponse.getHttpContent(), "UTF-8"));
            if (200 == jsonObject.getInteger("code")) {
                JSONArray taskResults = jsonObject.getJSONArray("data");
                for (Object taskResult : taskResults) {
                    if (200 == ((JSONObject) taskResult).getInteger("code")) {
                        String taskId = ((JSONObject) taskResult).getString("taskId");
                        return taskId;
                    }
                }
            }
        } else {
            log.error("response not success. status:" + httpResponse.getStatus());
        }
        return null;
    }

    public Integer doLoopGetVideoCheckRes(String taskId) throws UnsupportedEncodingException, ClientException, JsonProcessingException {
        IClientProfile profile = DefaultProfile.getProfile("cn-shanghai", access_key, access_secret);
        DefaultProfile.addEndpoint("cn-shanghai", "Green", "green.cn-shanghai.aliyuncs.com");
        IAcsClient client = new DefaultAcsClient(profile);

        VideoAsyncScanResultsRequest videoAsyncScanResultsRequest = new VideoAsyncScanResultsRequest();
        videoAsyncScanResultsRequest.setAcceptFormat(FormatType.JSON);

        List<String> taskList = new ArrayList<String>();
        // 这里添加要查询的TaskId。提交任务的时候需要自行保存TaskId。
        taskList.add(taskId);

        videoAsyncScanResultsRequest.setHttpContent(JSON.toJSONString(taskList).getBytes("UTF-8"), "UTF-8", FormatType.JSON);

        /**
         * 请务必设置超时时间。
         */
        videoAsyncScanResultsRequest.setConnectTimeout(3000);
        videoAsyncScanResultsRequest.setReadTimeout(6000);
            HttpResponse httpResponse = client.doAction(videoAsyncScanResultsRequest);
            if(httpResponse.isSuccess()){
                JSONObject scrResponse = JSON.parseObject(new String(httpResponse.getHttpContent(), "UTF-8"));
                if (200 == scrResponse.getInteger("code")) {
                    JSONArray taskResults = scrResponse.getJSONArray("data");
                    //获取任务id

                    for (Object taskResult : taskResults) {
                        if (200 == ((JSONObject) taskResult).getInteger("code")) {
                            JSONArray sceneResults = ((JSONObject) taskResult).getJSONArray("results");
                            for (Object sceneResult : sceneResults) {
                                String scene = ((JSONObject) sceneResult).getString("scene");
                                String suggestion = ((JSONObject) sceneResult).getString("suggestion");
                                //根据scene和suggetion做相关的处理
                                log.info("当前视频审核场景 scene = [" + scene + "]");
                                System.out.println("当前审核建议 suggestion = [" + suggestion + "]");
                                if (!"pass".equals(suggestion)){
                                    return -1;
                                }else {
                                    return 1;
                                }
                            }
                        } else {
                            Integer code = ((JSONObject) taskResult).getInteger("code");
                            log.error("task process fail:" + code);
                            if(code==280)
                            {
                                //视频还在审核中
                                return 280;
                            }
                        }
                    }
                } else {
                    log.error("detect not success. code:" + scrResponse.getInteger("code"));
                }
            }else{
                log.error("response not success. status:" + httpResponse.getStatus());
            }
                  return -1;
    }
}
